const blocks = "(if|else if|await|then|catch|each|html|debug)";

Prism.languages.svelte = Prism.languages.extend("markup", {
	each: {
		pattern: new RegExp(
			"{[#/]each" + "(?:(?:\\{(?:(?:\\{(?:[^{}])*\\})|(?:[^{}]))*\\})|(?:[^{}]))*}"
		),
		inside: {
			"language-javascript": [
				{
					pattern: /(as[\s\S]*)\([\s\S]*\)(?=\s*\})/,
					lookbehind: true,
					inside: Prism.languages["javascript"],
				},
				{
					pattern: /(as[\s]*)[\s\S]*(?=\s*)/,
					lookbehind: true,
					inside: Prism.languages["javascript"],
				},
				{
					pattern: /(#each[\s]*)[\s\S]*(?=as)/,
					lookbehind: true,
					inside: Prism.languages["javascript"],
				},
			],
			keyword: /[#/]each|as/,
			punctuation: /{|}/,
		},
	},
	block: {
		pattern: new RegExp(
			"{[#:/@]/s" + blocks + "(?:(?:\\{(?:(?:\\{(?:[^{}])*\\})|(?:[^{}]))*\\})|(?:[^{}]))*}"
		),
		inside: {
			punctuation: /^{|}$/,
			keyword: [new RegExp("[#:/@]" + blocks + "( )*"), /as/, /then/],
			"language-javascript": {
				pattern: /[\s\S]*/,
				inside: Prism.languages["javascript"],
			},
		},
	},
	tag: {
		pattern:
			/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?:"[^"]*"|'[^']*'|{[\s\S]+?}(?=[\s/>])))|(?=[\s/>])))+)?\s*\/?>/i,
		greedy: true,
		inside: {
			tag: {
				pattern: /^<\/?[^\s>\/]+/i,
				inside: {
					punctuation: /^<\/?/,
					namespace: /^[^\s>\/:]+:/,
				},
			},
			"language-javascript": {
				pattern: /\{(?:(?:\{(?:(?:\{(?:[^{}])*\})|(?:[^{}]))*\})|(?:[^{}]))*\}/,
				inside: Prism.languages["javascript"],
			},
			"attr-value": {
				pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/i,
				inside: {
					punctuation: [
						/^=/,
						{
							pattern: /^(\s*)["']|["']$/,
							lookbehind: true,
						},
					],
					"language-javascript": {
						pattern: /{[\s\S]+}/,
						inside: Prism.languages["javascript"],
					},
				},
			},
			punctuation: /\/?>/,
			"attr-name": {
				pattern: /[^\s>\/]+/,
				inside: {
					namespace: /^[^\s>\/:]+:/,
				},
			},
		},
	},
	"language-javascript": {
		pattern: /\{(?:(?:\{(?:(?:\{(?:[^{}])*\})|(?:[^{}]))*\})|(?:[^{}]))*\}/,
		lookbehind: true,
		inside: Prism.languages["javascript"],
	},
});

Prism.languages.svelte["tag"].inside["attr-value"].inside["entity"] =
	Prism.languages.svelte["entity"];

Prism.hooks.add("wrap", (env) => {
	if (env.type === "entity") {
		env.attributes["title"] = env.content.replace(/&amp;/, "&");
	}
});

Object.defineProperty(Prism.languages.svelte.tag, "addInlined", {
	value: function addInlined(tagName, lang) {
		const includedCdataInside = {};
		includedCdataInside["language-" + lang] = {
			pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,
			lookbehind: true,
			inside: Prism.languages[lang],
		};
		includedCdataInside["cdata"] = /^<!\[CDATA\[|\]\]>$/i;

		const inside = {
			"included-cdata": {
				pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
				inside: includedCdataInside,
			},
		};
		inside["language-" + lang] = {
			pattern: /[\s\S]+/,
			inside: Prism.languages[lang],
		};

		const def = {};
		def[tagName] = {
			pattern: RegExp(
				/(<__[\s\S]*?>)(?:<!\[CDATA\[[\s\S]*?\]\]>\s*|[\s\S])*?(?=<\/__>)/.source.replace(
					/__/g,
					tagName
				),
				"i"
			),
			lookbehind: true,
			greedy: true,
			inside,
		};

		Prism.languages.insertBefore("svelte", "cdata", def);
	},
});

Prism.languages.svelte.tag.addInlined("style", "css");
Prism.languages.svelte.tag.addInlined("script", "javascript");
